package com.innerchic.mapper.database;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.innerchic.mapper.database.annotation.InTable;
import com.innerchic.mapper.database.annotation.Insignificance;
import com.innerchic.mapper.database.annotation.PrimaryKey;
import com.innerchic.mapper.log.Logger;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * ================================================
 * 作    者：贾恒飞 >>> 17515250730@163.com
 * 项    目：young
 * 日    期：2021/11/3 11:08
 * 包    名：com.innerchic.mapper.database
 * 描    述：数据库操作
 * Create by zFox from AndroidStudio4.2
 * ================================================
 */
public final class DatabaseOperation {

    /**
     * 查询方法
     *
     * @param rdb         可读数据库对象
     * @param selectClass 要映射的类对象
     * @param table       表名
     * @param columns     要查询的字段列名
     * @param where       条件语句
     * @param whereValue  条件语句参数
     * @param groupBy     GROUP BY
     * @param having      HAVING
     * @param orderBy     排序
     * @param limit       分页
     * @param <Bean>      类对象泛型
     * @return 查询结果集合, 无结果则返回空集合
     */
    static <Bean> List<Bean> query(SQLiteDatabase rdb, Class<Bean> selectClass,
                                   String table, String[] columns, String where, String[] whereValue, String groupBy, String having, String orderBy, String limit) {
        List<Bean> queryResult = new ArrayList<>();
        if (rdb == null) {
            return queryResult;
        }
        //查询
        Cursor cursor = null;
        try {
            cursor = rdb.query(table, columns, where, whereValue, groupBy, having, orderBy, limit);
        } catch (Exception e) {
            Logger.e(e, "query()时游标异 -> @-[@-]", table, selectClass.getSimpleName());
        }
        if (cursor == null) {
            return queryResult;
        }
        //解析游标值
        while (cursor.moveToNext()) {
            Bean bean = workshop(selectClass, cursor);
            if (bean == null) {
                cursor.close();
                return queryResult;
            }
            queryResult.add(bean);
        }
        //关闭游标
        cursor.close();
        return queryResult;
    }

    /**
     * 使用sql查询
     *
     * @param rdb         可读数据库对象
     * @param selectClass 要映射的类对象
     * @param sql         sql语句
     * @param whereValue  sql语句参数
     * @param <Bean>      类对象泛型
     * @return 查询结果集合, 无结果则返回空集合
     */
    static <Bean> List<Bean> rawQuery(SQLiteDatabase rdb, Class<Bean> selectClass,
                                      String sql, String[] whereValue) {
        List<Bean> queryResult = new ArrayList<>();
        if (rdb == null) {
            return queryResult;
        }
        //查询
        Cursor cursor = null;
        try {
            cursor = rdb.rawQuery(sql, whereValue);
        } catch (Exception e) {
            Logger.e(e, "rawQuery()时游标异 -> @-[@-]", selectClass.getSimpleName(), sql);
        }
        if (cursor == null) {
            return queryResult;
        }
        while (cursor.moveToNext()) {
            Bean bean = workshop(selectClass, cursor);
            if (bean == null) {
                cursor.close();
                return queryResult;
            }
            queryResult.add(bean);
        }
        //关闭游标
        cursor.close();
        return queryResult;
    }

    /**
     * 查询是否存在
     *
     * @param rdb        可读数据库对象
     * @param sql        sql语句
     * @param whereValue sql语句参数
     * @return true存在
     */
    static boolean exist(SQLiteDatabase rdb,
                         String sql, String[] whereValue) {
        Cursor cursor = null;
        try {
            cursor = rdb.rawQuery(sql, whereValue);
        } catch (Exception e) {
            Logger.e(e, "exist()游标异常");
        }
        if (cursor == null) {
            return false;
        }
        boolean toFirst = cursor.moveToFirst();
        cursor.close();
        return toFirst;
    }

    /**
     * 更新一条数据
     *
     * @param wdb          可写数据库
     * @param inUpdateBean 要更新的数据对象
     * @param table        表名
     * @param where        条件语句
     * @param whereValue   条件语句参数
     * @param isExcludeId  是否排除主键,默认true,不会修改<Bean>中的主键值
     * @param <Bean>       类对象泛型
     * @return 受影响的条数, 0标识失败
     */
    static <Bean> int update(SQLiteDatabase wdb, Bean inUpdateBean,
                             String table, String where, String[] whereValue, boolean isExcludeId) {
        if (wdb == null || inUpdateBean == null) {
            return -1;
        }
        ContentValues saveValue = new ContentValues();
        Field[] fields = inUpdateBean.getClass().getDeclaredFields();
        for (Field field : fields) {
            Insignificance insignificance = field.getAnnotation(Insignificance.class);
            if (insignificance != null) {
                continue;
            }
            //排除id
            PrimaryKey annotation = field.getAnnotation(PrimaryKey.class);
            if (annotation != null && isExcludeId) {
                continue;
            }
            //解析其他参数
            field.setAccessible(true);
            try {
                Object value = field.get(inUpdateBean);
                //排除空值
                if (value == null) {
                    continue;
                }
                //排除0项
                if ((field.getType() == int.class || field.getType() == long.class || field.getType() == double.class)
                        && "0".equals(String.valueOf(value))) {
                    continue;
                }
                InTable inTable = field.getAnnotation(InTable.class);
                if (inTable == null) {
                    continue;
                }
                saveValue.put(inTable.value(), String.valueOf(value));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return wdb.update(table, saveValue, where, whereValue);
    }

    /**
     * 根据条件修改单个参数
     *
     * @param wdb        可写数据库
     * @param table      表名
     * @param key        修改的字段名
     * @param value      修改的字段值
     * @param where      条件语句
     * @param whereValue 条件语句对象
     * @return 受影响的条数, 0标识失败
     */
    static int update(SQLiteDatabase wdb,
                      String table, String key, Object value, String where, String[] whereValue) {
        if (wdb == null) {
            return -1;
        }
        ContentValues cv = new ContentValues();
        cv.put(key, String.valueOf(value));
        return wdb.update(table, cv, where, whereValue);
    }

    /**
     * 删除表数据
     *
     * @param wdb        可写数据库
     * @param table      表名
     * @param where      条件语句
     * @param whereValue 条件语句对象
     * @return 受影响的条数, 0标识没有删除项
     */
    static int delete(SQLiteDatabase wdb,
                      String table, String where, String[] whereValue) {
        if (wdb == null) {
            return -1;
        }
        return wdb.delete(table, where, whereValue);
    }

    /**
     * 插入数据
     *
     * @param wdb            可写数据库
     * @param inStall        插入的数据对象
     * @param table          表名
     * @param nullColumnHack 空列
     * @param <Bean>         泛型对象
     * @return 存入的主键id
     */
    static <Bean> long insert(SQLiteDatabase wdb, Bean inStall,
                              String table, String nullColumnHack) {
        if (wdb == null || inStall == null) {
            return -1;
        }
        ContentValues saveValue = new ContentValues();
        Field[] fields = inStall.getClass().getDeclaredFields();
        for (Field field : fields) {
            Insignificance insignificance = field.getAnnotation(Insignificance.class);
            if (insignificance != null) {
                continue;
            }
            //排除id->自增id跳过
            PrimaryKey annotation = field.getAnnotation(PrimaryKey.class);
            if (annotation != null && annotation.isAuto()) {
                continue;
            }
            field.setAccessible(true);
            try {
                Object value = field.get(inStall);
                if (value == null) {
                    continue;
                }
                InTable inTable = field.getAnnotation(InTable.class);
                if (inTable == null) {
                    continue;
                }
                saveValue.put(inTable.value(), String.valueOf(value));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return wdb.insert(table, nullColumnHack, saveValue);
    }

    /**
     * 判断并转换类型
     *
     * @param type 变量类型
     * @param str  字符串的值
     * @return 转化为指定变量类型的值
     */
    private static Object typeResult(Class<?> type, String str) {
        if (type == int.class || type == Integer.class) return Integer.valueOf(str);
        if (type == boolean.class || type == Boolean.class) return Boolean.valueOf(str);
        if (type == long.class || type == Long.class) return Long.valueOf(str);
        if (type == double.class || type == Double.class) return Double.valueOf(str);
        if (type == float.class || type == Float.class) return Float.valueOf(str);
        return str;
    }

    /**
     * 装订工厂
     *
     * @param selectClass 查询类对象
     * @param cursor      游标引用
     * @param <Bean>      返回泛型
     * @return 如果为null标识初始化失败, 直接return
     */
    private static <Bean> Bean workshop(Class<Bean> selectClass, Cursor cursor) {
        Bean bean;
        try {
            bean = selectClass.newInstance();
        } catch (IllegalAccessException | InstantiationException e) {
            Logger.e(e, "query()初始化查询对象异常");
            return null;
        }
        Field[] fields = selectClass.getDeclaredFields();
        for (Field field : fields) {
            Insignificance insignificance = field.getAnnotation(Insignificance.class);
            if (insignificance != null) {
                continue;
            }
            //拿到字段名
            InTable annotation = field.getAnnotation(InTable.class);
            if (annotation == null) {
                continue;
            }
            String fieldName = annotation.value();
            if ("".equals(fieldName)) {
                fieldName = field.getName();
            }
            int columnIndex = cursor.getColumnIndex(fieldName);
            if (columnIndex < 0) {
                Logger.d("query()不存在的字段:@-", fieldName);
                continue;
            }
            String cursorString = cursor.getString(columnIndex);
            field.setAccessible(true);
            try {
                field.set(bean, typeResult(field.getType(), cursorString));
            } catch (IllegalAccessException e) {
                Logger.e(e, "query()参数[@-]赋值时失败", fieldName);
            }
        }
        return bean;
    }

}
